package com.ricchieri.service;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;

import com.ricchieri.bean.FixedReservationBean;
import com.ricchieri.common.BusinessSettings;
import com.ricchieri.common.CustomAuthenticationToken;
import com.ricchieri.filter.BasicFilter;
import com.ricchieri.filter.EmailTemplateFilter;
import com.ricchieri.filter.ScheduleCharterFilter;
import com.ricchieri.filter.TripFilter;
import com.ricchieri.model.EmailTemplate;
import com.ricchieri.model.EmailToSend;
import com.ricchieri.model.MeanPayment;
import com.ricchieri.model.PassengerType;
import com.ricchieri.model.Reservation;
import com.ricchieri.model.ReservationType;
import com.ricchieri.model.ScheduleCharter;
import com.ricchieri.model.Trip;
import com.ricchieri.model.User;
import com.ricchieri.service.interf.IEmailTemplateService;
import com.ricchieri.service.interf.IEmailToSendService;
import com.ricchieri.service.interf.IFixedReservationService;
import com.ricchieri.service.interf.IMeanPaymentService;
import com.ricchieri.service.interf.IPassengerTypeService;
import com.ricchieri.service.interf.IReservationService;
import com.ricchieri.service.interf.IReservationTypeService;
import com.ricchieri.service.interf.IScheduleCharterService;
import com.ricchieri.service.interf.ITripService;
import com.ricchieri.util.DateUtil;
import com.ricchieri.util.FacesUtil;

@Transactional(readOnly = true)
public class FixedReservationService implements IFixedReservationService, Serializable {

	private static final long serialVersionUID = -6240491024413958995L;
	
	IEmailToSendService emailToSendService;
	IEmailTemplateService emailTemplateService;
	IReservationService reservationService;
	IScheduleCharterService scheduleCharterService;
	IReservationTypeService reservationTypeService;
	ITripService tripService;
	IMeanPaymentService meanPaymentService;
	IPassengerTypeService passengerTypeService;
	
	
	@Override
	public Boolean validateAvailability(FixedReservationBean fixedReservationBean, String form, Boolean showErrors) {
		
		String daysWithNoCapacity = "";
		String daysNotScheduleCharter = "";
		int dayInRange;
		
		List<ScheduleCharter> scheduleCharters = obtainScheduleCharters(fixedReservationBean);
		
		if(scheduleCharters.isEmpty()) {
			if(showErrors) {
				FacesUtil.showFatalMessage(form, "notExistScheduleCharter");
				return Boolean.FALSE;
			}
		} else {
			for (ScheduleCharter scheduleCharter : scheduleCharters) {
				if(scheduleCharter.getQuantityReserved() >= scheduleCharter.getCharter().getPlaces()) {
					
					dayInRange = DateUtil.obtainDayOfWeekWithAdd(fixedReservationBean.getStartDate(), 0);
					if(daysWithNoCapacity.length() > 0 && fixedReservationBean.getSelectedDays().contains(String.valueOf(dayInRange))) {
						daysWithNoCapacity = daysWithNoCapacity.concat(", ");
					}
					
					daysWithNoCapacity = daysWithNoCapacity.concat(DateUtil.formatDate(scheduleCharter.getSchedule().getDate()));
				}
			}
			
			int daysInRange = DateUtil.daysBetween(fixedReservationBean.getStartDate(), fixedReservationBean.getFinishDate()) + 1;

			Date newDate;;
			for (int i = 0; i < daysInRange; i++) {
				dayInRange = DateUtil.obtainDayOfWeekWithAdd(fixedReservationBean.getStartDate(), i);
				newDate = DateUtil.addDays(fixedReservationBean.getStartDate(), i);
				newDate = DateUtil.converToDate(newDate, fixedReservationBean.getTimeWithFormat());
						
				if(fixedReservationBean.getSelectedDays().contains(String.valueOf(dayInRange)) && checkDateInRange(scheduleCharters, newDate) == null) {
					if(daysNotScheduleCharter.length() > 0) {
						daysNotScheduleCharter = daysNotScheduleCharter.concat(", ");
					}
					
					daysNotScheduleCharter = daysNotScheduleCharter.concat(DateUtil.formatDate(newDate));					
				}
			}
			
			if(daysWithNoCapacity.length() > 0 && showErrors) {
				FacesUtil.showFatalMessage(form, "notCapacityScheduleCharter", daysWithNoCapacity);
			}
			
			if(daysNotScheduleCharter.length() > 0 && showErrors) {
				FacesUtil.showFatalMessage(form, "notExistScheduleCharterRange", daysNotScheduleCharter);
			}
			
			if(daysNotScheduleCharter.length() > 0 || daysNotScheduleCharter.length() > 0) {
				return Boolean.FALSE;
			} else {
				FacesUtil.showInfoMessage(form, "correctTimeSchedule");
			}
		}

		return Boolean.TRUE;
	}
	

	private ScheduleCharter checkDateInRange(List<ScheduleCharter> scheduleCharters, Date date) {
		Date scheduleDate;
		for (ScheduleCharter scheduleCharter : scheduleCharters) {
			scheduleDate = DateUtil.converToDate(scheduleCharter.getSchedule().getDate(), scheduleCharter.getSchedule().getTime());
			if(scheduleDate.getTime() == date.getTime()) {
				return scheduleCharter;
			}
		}
		return null;
	}
	
	private List<ScheduleCharter> obtainScheduleCharters(FixedReservationBean fixedReservationBean) {
		ScheduleCharterFilter filter = new ScheduleCharterFilter();
		filter.setStart(fixedReservationBean.getStartDate());
		filter.setFinish(fixedReservationBean.getFinishDate());
		filter.setTrip(fixedReservationBean.getTrip());
		filter.setTime(fixedReservationBean.getTimeWithFormat());
		List <ScheduleCharter> scheduleCharters = getIScheduleCharterService().getAllScheduleCharterByFilter(filter);
		return scheduleCharters;
	}


	public IScheduleCharterService getIScheduleCharterService() {
		return scheduleCharterService;
	}


	public void setIScheduleCharterService(
			IScheduleCharterService scheduleCharterService) {
		this.scheduleCharterService = scheduleCharterService;
	}


	@Override
	@Transactional(readOnly = false)
	public Boolean generateReservation(FixedReservationBean fixedReservationBean,
			User selectedUser) {
		
		int dayInRange;
		int daysInRange = DateUtil.daysBetween(fixedReservationBean.getStartDate(), fixedReservationBean.getFinishDate()) + 1;
		Date newDate;
		ScheduleCharter scheduleCharter;
		Reservation reservation;
		
		List<ScheduleCharter> scheduleCharters = obtainScheduleCharters(fixedReservationBean);
		
		if(scheduleCharters.isEmpty()) {
			return Boolean.FALSE;
		} else {
			User currentUser = ((CustomAuthenticationToken)SecurityContextHolder.getContext().getAuthentication()).getUser();
			for (int i = 0; i < daysInRange; i++) {
				newDate = DateUtil.addDays(fixedReservationBean.getStartDate(), i);
				newDate = DateUtil.converToDate(newDate, fixedReservationBean.getTimeWithFormat());
				
				dayInRange = DateUtil.obtainDayOfWeekWithAdd(fixedReservationBean.getStartDate(), i);
				scheduleCharter = checkDateInRange(scheduleCharters, newDate);
				
				if(fixedReservationBean.getSelectedDays().contains(String.valueOf(dayInRange)) && scheduleCharter != null
						&& scheduleCharter.getQuantityReserved() < scheduleCharter.getCharter().getPlaces()) {
					reservation = new Reservation();
					
					reservation.setCost(fixedReservationBean.getCost());
					reservation.setDownOn(fixedReservationBean.getDownOn());
					reservation.setMeanPayment(obtainMeanPayment(fixedReservationBean));
					reservation.setObservation(fixedReservationBean.getObservation());
					reservation.setOperator(currentUser);
					reservation.setPassengerType(obtainPassengerType(fixedReservationBean));
					reservation.setReservationDate(new Date(System.currentTimeMillis()));
					reservation.setReservationType(obtainReservationType(fixedReservationBean));
					reservation.setScheduleCharter(scheduleCharter);
					reservation.setUpOn(fixedReservationBean.getUpOn());
					reservation.setUser(selectedUser);
					
					if(!haveReservation(selectedUser, scheduleCharter)) {
						getReservationService().addReservationWithoutEmail(reservation);
					}
				}
			}
			this.createFixedReservationEmail(fixedReservationBean, selectedUser, currentUser);
		}
		return Boolean.TRUE;
	}

	public Boolean haveReservation(User user, ScheduleCharter scheduleCharter) {
		for (Reservation reservation : scheduleCharter.getActiveReservations()) {
			if(reservation.getUser().getId() == user.getId()) {
				return Boolean.TRUE;
			}
		}
		return Boolean.FALSE;
	}
	
	public IEmailToSendService getEmailToSendService() {
		return emailToSendService;
	}

	public void setEmailToSendService(IEmailToSendService emailToSendService) {
		this.emailToSendService = emailToSendService;
	}

	public IEmailTemplateService getEmailTemplateService() {
		return emailTemplateService;
	}

	public void setEmailTemplateService(IEmailTemplateService emailTemplateService) {
		this.emailTemplateService = emailTemplateService;
	}

	public IReservationService getReservationService() {
		return reservationService;
	}

	public void setReservationService(IReservationService reservationService) {
		this.reservationService = reservationService;
	}

	public IScheduleCharterService getScheduleCharterService() {
		return scheduleCharterService;
	}

	public void setScheduleCharterService(
			IScheduleCharterService scheduleCharterService) {
		this.scheduleCharterService = scheduleCharterService;
	}

	public IReservationTypeService getReservationTypeService() {
		return reservationTypeService;
	}

	public void setReservationTypeService(
			IReservationTypeService reservationTypeService) {
		this.reservationTypeService = reservationTypeService;
	}

	public ITripService getTripService() {
		return tripService;
	}

	public void setTripService(ITripService tripService) {
		this.tripService = tripService;
	}

	public IMeanPaymentService getMeanPaymentService() {
		return meanPaymentService;
	}

	public void setMeanPaymentService(IMeanPaymentService meanPaymentService) {
		this.meanPaymentService = meanPaymentService;
	}

	public IPassengerTypeService getPassengerTypeService() {
		return passengerTypeService;
	}

	public void setPassengerTypeService(IPassengerTypeService passengerTypeService) {
		this.passengerTypeService = passengerTypeService;
	}
	
	private MeanPayment obtainMeanPayment(FixedReservationBean fixedReservationBean) {
		BasicFilter meanPaymentFilter = new BasicFilter();
		meanPaymentFilter.setId(Integer.valueOf(fixedReservationBean.getSelectedMeanPayment()));
		return getMeanPaymentService().getMeanPaymentById(meanPaymentFilter);
	}
	
	private PassengerType obtainPassengerType(FixedReservationBean fixedReservationBean) {
		BasicFilter passengerTypeFilter = new BasicFilter();
		passengerTypeFilter.setId(Integer.valueOf(fixedReservationBean.getSelectedPassengerType()));
		return getPassengerTypeService().getPassengerTypeById(passengerTypeFilter);
	}
	
	private ReservationType obtainReservationType(FixedReservationBean fixedReservationBean) {
		BasicFilter reservationTypeFilter = new BasicFilter();
		reservationTypeFilter.setId(Integer.valueOf(fixedReservationBean.getSelectedReservationType()));
		return getReservationTypeService().getReservationTypeById(reservationTypeFilter);
	}
	
	private Trip obtainTrip(FixedReservationBean fixedReservationBean) {
		TripFilter tripFilter = new TripFilter();
		tripFilter.setId(Integer.valueOf(fixedReservationBean.getTrip()));
		return getTripService().getTripById(tripFilter);
	}

	private void createFixedReservationEmail(FixedReservationBean fixedReservationBean, User user, User currentUser) {		
		EmailTemplateFilter emailTemplateFilter = new EmailTemplateFilter();
		emailTemplateFilter.setEmailTemplateTypeDescription(BusinessSettings.EMAIL_TEMPLATE_FIXED_RESERVATION);
		EmailTemplate emailTemplate = emailTemplateService.getEmailTemplateByFilter(emailTemplateFilter);
		
		if(emailTemplate != null && user.getDefaultEmail() != null) {
			EmailToSend emailToSend = new EmailToSend();
			
			String content = emailTemplate.getTemplate();
			String origenTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_ORIGIN);
			String destinyTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_DESTINY);
			String fullNameTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_FULLNAME);
			String priceTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_TRAVEL_PRICE);
			String operatorTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_OPERATOR);
			String upOnTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_UP_ON);
			String downOnTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_DOWN_ON);
			
			String timeTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_TIME);
			String startDateTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_START_DATE);
			String finishDateTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_FINISH_DATE);
			String daysWeekTag = FacesUtil.getMessage(BusinessSettings.EMAIL_TAG_DAYS_WEEK);
			
			content = content.replace("{".concat(fullNameTag).concat("}"), user.getFullName());
			content = content.replace("{".concat(priceTag).concat("}"), String.valueOf(fixedReservationBean.getCost()));
			content = content.replace("{".concat(upOnTag).concat("}"), fixedReservationBean.getUpOn());
			content = content.replace("{".concat(downOnTag).concat("}"), fixedReservationBean.getDownOn());
			content = content.replace("{".concat(operatorTag).concat("}"), String.valueOf(currentUser.getFirstName()));
			
			content = content.replace("{".concat(finishDateTag).concat("}"), DateUtil.formatDate(fixedReservationBean.getFinishDate()));
			content = content.replace("{".concat(startDateTag).concat("}"), DateUtil.formatDate(fixedReservationBean.getStartDate()));
			content = content.replace("{".concat(timeTag).concat("}"), DateUtil.formatTime(fixedReservationBean.getTimeWithFormat()));
			
			content = content.replace("{".concat(daysWeekTag).concat("}"), fixedReservationBean.obtainDescriptionSelectedDays());
			
			Trip trip = obtainTrip(fixedReservationBean);

			content = content.replace("{".concat(origenTag).concat("}"), FacesUtil.getMessage(trip.getPlaceOrigin().getDescription()));
			content = content.replace("{".concat(destinyTag).concat("}"), FacesUtil.getMessage(trip.getPlaceDestiny().getDescription()));
					
			emailToSend.setUser(user);
			emailToSend.setMessageContent(content);
			emailToSend.setEmailToSendType(emailTemplate.getEmailToSendType());
			emailToSend.setSubjectContent(emailTemplate.getSubject());
			
			emailToSendService.add(emailToSend);
		}
	}
	
	
}
